package com.hexb.smh.controller.management;

import com.hexb.core.common.Page;
import com.hexb.core.utils.Assert;
import com.hexb.core.utils.MapBuilder;
import com.hexb.smh.annotations.AopOperationLog;
import com.hexb.smh.entity.Brand;
import com.hexb.smh.entity.Product;
import com.hexb.smh.entity.ProductRaw;
import com.hexb.smh.entity.enums.ImportStrategy;
import com.hexb.smh.entity.enums.LogType;
import com.hexb.smh.entity.enums.Operators;
import com.hexb.smh.entity.param.product.ProductParam;
import com.hexb.smh.entity.param.product.ProductQueryParam;
import com.hexb.smh.entity.view.ImportResult;
import com.hexb.smh.entity.view.ProductBrandView;
import com.hexb.smh.entity.view.ProductView;
import com.hexb.smh.errors.ErrorCodes;
import com.hexb.smh.service.IProductService;
import com.hexb.smh.utils.OperationConst;
import io.swagger.annotations.*;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

import static com.hexb.smh.utils.SmhConstant.ROLE_ADMIN;
import static com.hexb.smh.utils.SmhConstant.ROLE_SUPER_ADMIN;

/**
 * @author : hexb
 */
@RestController
@RequestMapping("/management/product")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Api(value = "A4*.项目管理", description = "Server", tags = {"A4*.项目管理"})
@Slf4j
public class ProductController {

    @NonNull
    final private IProductService productService;


    @ApiOperation("项目列表(分页)")
    @RequiresRoles(value = {ROLE_SUPER_ADMIN, ROLE_ADMIN}, logical = Logical.OR)
    @GetMapping("/{pageSize}/{pageNum}")
    public Page<ProductView> page(ProductQueryParam param,
                                  @PathVariable("pageSize") @ApiParam(value = "分页大小", example = "10") int pageSize,
                                  @PathVariable("pageNum") @ApiParam(value = "当前页", example = "1") int pageNum) {
        return productService.search(param, pageSize, pageNum);
    }

    @ApiOperation("添加项目")
    @AopOperationLog(type = LogType.product, name = OperationConst.APPEND_PRODUCT, operations = Operators.appendProduct)
    @RequiresRoles(value = {ROLE_SUPER_ADMIN, ROLE_ADMIN}, logical = Logical.OR)
    @PostMapping
    public ProductView append(@RequestBody @Valid ProductParam.ProductParamInsert param) {
        Product product = param.toProduct();
        productService.save(product);
        return productService.selectOneById(product.getId());
    }

    @ApiOperation("更新项目")
    @AopOperationLog(type = LogType.product, name = OperationConst.UPDATE_PRODUCT, operations = Operators.updateProduct)
    @RequiresRoles(value = {ROLE_SUPER_ADMIN, ROLE_ADMIN}, logical = Logical.OR)
    @PutMapping("/{id}")
    public ProductView update(@RequestBody @Valid ProductParam.ProductParamUpdate param, @PathVariable Integer id) {
        Product product = param.toProduct(id);
        productService.update(product);
        return productService.selectOneById(id);
    }

    @ApiOperation("获取项目详情")
    @RequiresRoles(value = {ROLE_SUPER_ADMIN, ROLE_ADMIN}, logical = Logical.OR)
    @GetMapping("/{id}")
    public ProductView get(@PathVariable("id") @ApiParam(value = "项目id", example = "1", required = true) int id) {
        return productService.selectOneById(id);
    }

    @ApiOperation("删除项目")
    @AopOperationLog(type = LogType.product, name = OperationConst.DELETE_PRODUCT, operations = Operators.deleteProduct)
    @RequiresRoles(value = {ROLE_SUPER_ADMIN, ROLE_ADMIN}, logical = Logical.OR)
    @DeleteMapping("/{id}")
    public int delete(@PathVariable("id") @ApiParam(value = "项目id", example = "1", required = true) int id) {
        return productService.delete(id);
    }

    @ApiOperation("删除项目(批量)")
    @AopOperationLog(type = LogType.product, name = OperationConst.DELETE_PRODUCT, operations = Operators.batchDeleteProduct)
    @RequiresRoles(value = {ROLE_SUPER_ADMIN, ROLE_ADMIN}, logical = Logical.OR)
    @DeleteMapping("/batch/{ids}")
    public int delete(@PathVariable("ids") @ApiParam(value = "项目id", example = "1", required = true) Integer[] ids) {
        return productService.deleteBatch(ids);
    }

    @ApiOperation("上/下架")
    @AopOperationLog(type = LogType.product, name = OperationConst.TOGGLE_PRODUCT, operations = Operators.toggleProduct)
    @RequiresRoles(value = {ROLE_SUPER_ADMIN, ROLE_ADMIN}, logical = Logical.OR)
    @PutMapping("/toggle/{id}")
    public int toggleActivated(@PathVariable("id") @ApiParam(value = "项目id", example = "1", required = true) int id,
                               Boolean activated) {
        return productService.toggleActivated(id, activated);
    }

    @ApiOperation("检查项目编号是否重复(true:有重复,不可使用该名称)")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "项目id(当编辑时需要排除正在编辑的项目时使用)")
            , @ApiImplicitParam(name = "name", value = "项目名")

    })
    @RequiresRoles(logical = Logical.OR, value = {ROLE_SUPER_ADMIN, ROLE_ADMIN})
    @GetMapping("/itemNo/checkDuplicate")
    public Boolean checkItemNoDuplicate(String itemNo, Integer id) {
        ProductRaw product = productService.findOneByMap(MapBuilder
                .<String, Object>create("itemNo", itemNo)
                .build("withoutId", id).map());
        return null != product;
    }


    @AopOperationLog(type = LogType.product, name = OperationConst.TOGGLE_PRODUCT, operations = Operators.batchToggleProduct)
    @ApiOperation("批量上/下架")
    @RequiresRoles(value = {ROLE_SUPER_ADMIN, ROLE_ADMIN}, logical = Logical.OR)
    @PutMapping("/batch/toggle/{ids}")
    public int batchDisableAdmin(
            @PathVariable Integer[] ids,
            Boolean activated) {
        return productService.updateActivatedBatch(ids, activated);
    }


    @AopOperationLog(type = LogType.product, name = OperationConst.IMPORT_PRODUCT, operations = Operators.none)
    @ApiOperation("导入项目")
    @RequiresRoles(logical = Logical.OR, value = {ROLE_SUPER_ADMIN, ROLE_ADMIN})
    @PostMapping("/import/{strategy}")
    public ImportResult<Product> importSalesman(@PathVariable @ApiParam("导入方式") ImportStrategy strategy,
                                                MultipartFile file) {
        String fileName = file.getOriginalFilename() != null ? file.getOriginalFilename().toLowerCase() : "";
        Assert.isFalse(fileName.endsWith("xls") || fileName.endsWith("xlsx"), ErrorCodes.NOT_EXCEL_FILE);
        return productService.importProduct(file, strategy);
    }

    @ApiOperation("获取全部项目(用于后端测试)")
    @RequiresRoles(logical = Logical.OR, value = {ROLE_SUPER_ADMIN, ROLE_ADMIN})
    @GetMapping("/list")
    public List<ProductBrandView> list(Integer brandId, String searchKey) {
        return productService.findWithBrandId(brandId == null ? Brand.DEFAULT : brandId, null, true, searchKey);
    }


    @ApiOperation("导出全部项目")
    @RequiresRoles(logical = Logical.OR, value = {ROLE_SUPER_ADMIN, ROLE_ADMIN})
    @GetMapping("/export")
    public void export(HttpServletResponse response) {
        ServletOutputStream os = null;
        try {
            response.setCharacterEncoding("utf-8");
            response.setContentType("multipart/form-data");
            response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("项目.xls", "utf-8"));
            os = response.getOutputStream();
            productService.export(os);
        } catch (IOException e) {
            log.error("获取输出流发生错误");
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                }
            }
        }
    }

}
